﻿using Ganjine;
using Ganjine.Common;
using Ganjine.DataModel;
using Ganjine_Windows10.Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using System.Xml;
using Windows.ApplicationModel.Core;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Popups;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Documents;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace Ganjine_Windows10
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class ItemPage : Page
    {
        private ObservableDictionary defaultViewModel = new ObservableDictionary();
        List<PoemItem> l = new List<PoemItem>();
        DataBridge2 pageDb;
        private string textTransition = "TLeft";
        bool settingFlyoutOpened = false;
        DispatcherTimer scrollSaveTimer = new DispatcherTimer();
        bool OnNavigatedToCalled = false;
        TypedEventHandler<DataTransferManager, DataRequestedEventArgs> ShareHandler_DataRequested;
        DataTransferManager dataTransferManager;

        const int eachBoxLength = 1000;

        public ItemPage()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Gets the DefaultViewModel. This can be changed to a strongly typed view model.
        /// </summary>
        public ObservableDictionary DefaultViewModel
        {
            get { return this.defaultViewModel; }
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            DataBridge2 db = Newtonsoft.Json.JsonConvert.DeserializeObject<DataBridge2>(e.Parameter.ToString());

            await Task.Run(() => { l = App.dataSource.GetListOfPoems(db.parentid); });

            InitPage(db, false);

            defaultViewModel["FontsList"] = App.fonts;



            slider.Value = App.DefaultFontSize;
            itemsControl.FontFamily = App.DefaultFont;

            OnNavigatedToCalled = true;

            base.OnNavigatedTo(e);
        }

        public async void InitPage(DataBridge2 db, bool CameBySwiping)
        {
            Debug.WriteLine("InitPage");
            scrollSaveTimer.Stop();

            if (db.HideNextPrevKeys)
            {
                PrevItemHeader.Visibility = Visibility.Collapsed;
                NextItemHeader.Visibility = Visibility.Collapsed;

                PhonePrevItemHeader.Visibility = Visibility.Collapsed;
                PhoneNextItemHeader.Visibility = Visibility.Collapsed;

                pivot.IsLocked = true;
            }
            pageDb = db;



            string sF = "";
            bool needsYeCorrection = false;
            if (App.DefaultFont != null)
            {
                sF = App.DefaultFont.Source.ToString();
            }

            if (sF.Contains("Nastaliq"))
            {
                needsYeCorrection = false;
            }
            else
            {
                needsYeCorrection = true;
            }

            Debug.WriteLine("InitPage: Fetching list of poems and set header texts");

            // Fetching list of poems moved to OnNavigatedTo, since we don't need to reload that in swipes. 
            SetHeaderTexts(db);

            await Task.Delay(100);

            loadingProgress.Visibility = Visibility.Visible;
            loadingProgress.IsActive = true;
            ShowProgressStoryboard.Begin();


            Debug.WriteLine("InitPage: Fetching verses");

            List<VerseItem2> verses = new List<VerseItem2>();
            await Task.Run(() => { verses = App.dataSource.GetVerses2(db.id); });

            if (needsYeCorrection)
            {
                for (int i = 0; i < verses.Count; i++)
                {
                    verses[i].text = verses[i].text.Replace("هٔ", "ة‌"); //Haz nim-faseleh after ة
                }
            }

            Debug.WriteLine("InitPage: Settings verse data to UI");
            SetVerseData(verses, textTransition);

            Debug.WriteLine("InitPage: Fav");
            var a = (from PoemItem p in App.favorites
                     where p.ID == db.id
                     select p).ToList();

            DeterminateFavButtonVisibility(db);


            Debug.WriteLine("InitPage: Scroll position");

            ScrollViewer scrollViewer = VisualChildFinder.FindVisualChild<ScrollViewer>(itemsControl);
            if (CameBySwiping)
                scrollViewer.ChangeView(scrollViewer.HorizontalOffset, 0, scrollViewer.ZoomFactor, true);

            await Task.Delay(CameBySwiping ? 150 : 20);

            HideProgressStoryboard.Begin();

            try
            {
                double scrollPos = GetScrollPosition(db.id);
                Debug.WriteLine(" **** " + scrollViewer.ExtentHeight.ToString());
                scrollViewer.ChangeView(scrollViewer.HorizontalOffset, scrollPos * scrollViewer.ExtentHeight, scrollViewer.ZoomFactor, false);
            }
            catch { }



            Debug.WriteLine("InitPage almost finished.");

            await Task.Delay(200);
            
            scrollSaveTimer.Start();

            await Task.Delay(200);

            loadingProgress.IsActive = false;
            loadingProgress.Visibility = Visibility.Collapsed;

            Debug.WriteLine("InitPage finished.");
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            scrollSaveTimer.Stop();
            scrollSaveTimer.Tick -= scrollSaveTimer_Tick;
            dataTransferManager.DataRequested -= ShareHandler_DataRequested;
            if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
                Windows.Phone.UI.Input.HardwareButtons.BackPressed -= HardwareButtons_BackPressed;

            base.OnNavigatingFrom(e);
        }

        private void SetVerseData(List<VerseItem2> verses, string transition)
        {
            itemsControl.Items.Clear();

            if (verses.Count == 0)
                return;

            int maxPos = ((VerseItem2)verses.OrderByDescending(i => i.position).FirstOrDefault()).position;
            int minPos = ((VerseItem2)verses.OrderBy(i => i.position).FirstOrDefault()).position;

            //Fix some poems
            int maxPosCount = (from VerseItem2 v in verses
                               where v.position == maxPos
                               select v).ToList().Count;

            if (maxPosCount + 3 >= verses.Count)
            {
                for (int i = 0; i < verses.Count; i++)
                {
                    if (verses[i].position == maxPos)
                    {
                        verses[i].position = minPos;
                    }
                    else if (verses[i].position == minPos)
                    {
                        verses[i].position = minPos + 1;
                    }
                }
                maxPos = ((VerseItem2)verses.OrderByDescending(i => i.position).FirstOrDefault()).position;
            }

            Dictionary<int, List<Paragraph>> pageData = new Dictionary<int, List<Paragraph>>();
            for (int i = 0; i < ((verses.Count / eachBoxLength) + 1); i++)
            {
                pageData.Add(i, new List<Paragraph>());
            }


            if ((minPos == -1) && (maxPos == minPos)) //This is plain text, or line by line poet
            {
                int counter = 0;
                foreach (VerseItem2 item in verses)
                {
                    Paragraph p = new Paragraph();
                    Run r = new Run();
                    r.Text = item.text;
                    r.FlowDirection = FlowDirection.RightToLeft;
                    p.Inlines.Add(r);
                    pageData[counter / eachBoxLength].Add(p);
                    counter++;
                }
            }
            else if (minPos == -1) //Mixture of poet and text
            {
                int counter = 0;
                foreach (VerseItem2 item in verses)
                {
                    Paragraph p = new Paragraph();

                    Run r = new Run();
                    r.Text = item.text;
                    r.FlowDirection = FlowDirection.RightToLeft;
                    p.Inlines.Add(r);

                    if (this.Width < 700)
                    {
                        if (item.position == 0)
                        {
                            p.TextAlignment = TextAlignment.Left;
                            p.Margin = new Thickness(10, 0, 0, 0);
                        }
                        else if (item.position > 0)
                        {
                            p.TextAlignment = TextAlignment.Right;
                            p.Margin = new Thickness(0, 0, 10, 25);
                        }
                    }
                    else
                    {
                        if (item.position == 0)
                        {
                            p.TextAlignment = TextAlignment.Center;
                            p.Margin = new Thickness(0, 0, 60, 0);
                        }
                        else if (item.position > 0)
                        {
                            p.TextAlignment = TextAlignment.Center;
                            p.Margin = new Thickness(60, 0, 0, 25);
                        }
                    }

                    pageData[counter / eachBoxLength].Add(p);
                    counter++;
                }
            }
            else if (maxPos > 1) //This is new poet
            {
                int counter = 0;
                foreach (VerseItem2 item in verses)
                {
                    Paragraph p = new Paragraph();
                    Run r = new Run();

                    p.Margin = new Thickness(0, 10, 0, 0);

                    string tabsBefore = "";
                    for (int i = 0; i < (item.position - minPos); i++)
                        tabsBefore += "\t\t";


                    r.Text = tabsBefore + item.text;
                    r.FlowDirection = FlowDirection.RightToLeft;
                    p.Inlines.Add(r);

                    pageData[counter / eachBoxLength].Add(p);
                    counter++;
                }

            }
            else //This is classic poet
            {
                int counter = 0;
                foreach (VerseItem2 item in verses)
                {
                    Paragraph p = new Paragraph();

                    p.Margin = new Thickness(0, 10, 0, 0);

                    Run r = new Run();
                    r.Text = item.text;
                    r.FlowDirection = FlowDirection.RightToLeft;
                    p.Inlines.Add(r);


                    if (item.position == 0)
                    {
                        p.TextAlignment = TextAlignment.Left;
                        p.Margin = new Thickness(0, 0, 0, 0);
                    }
                    else if (item.position > 0)
                    {
                        p.TextAlignment = TextAlignment.Right;
                        p.Margin = new Thickness(0, 0, 0, 25);
                    }

                    pageData[counter / eachBoxLength].Add(p);
                    counter++;
                }
            }

            const string richTextBlockTemplate = @"<RichTextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" 
                                                    Padding=""20,0,20,0"" Margin=""0,0,0,0""></RichTextBlock>";

            const string topBlockTemplate = @"<TextBlock xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" Height=""{0}"" />";


            if (UIViewSettings.GetForCurrentView().UserInteractionMode != UserInteractionMode.Mouse)
            {
                TextBlock tb = (TextBlock)XamlReader.Load(topBlockTemplate.Replace("{0}", (PhoneHeader.Height + 8).ToString()));
                itemsControl.Items.Add(tb);
            }

            foreach (var idx in pageData)
            {
                RichTextBlock rtb = (RichTextBlock)XamlReader.Load(richTextBlockTemplate);
                foreach (var item in pageData[idx.Key])
                {
                    rtb.Blocks.Add(item);
                }
                itemsControl.Items.Add(rtb);
            }

        }


        private void PreviousPage()
        {
            List<string> s = new List<string>();

            //await MyWebView.InvokeScriptAsync("goToLeft", s);

            if (l.Count == 0) { return; }
            int j = 0;

            for (int i = 0; i < l.Count; i++)
            {
                if (l[i].ID == pageDb.id)
                {
                    j = i;
                    break;
                }
            }

            j -= 1;
            if (j < 0)
            {
                j = l.Count - 1;
            }
            DataBridge2 dba = new DataBridge2()
            {
                parentid = pageDb.parentid,
                id = l[j].ID,
                title = l[j].Text
            };

            textTransition = "TRight";
            //await Task.Delay(TimeSpan.FromMilliseconds(200));
            InitPage(dba, true);
        }

        private void NextPage()
        {
            Debug.WriteLine("NextPage");
            List<string> s = new List<string>();

            //await MyWebView.InvokeScriptAsync("goToRight", s);

            if (l.Count == 0) { return; }
            int j = l.Count - 1;
            for (int i = 0; i < l.Count; i++)
            {
                if (l[i].ID == pageDb.id)
                {
                    j = i;
                    break;
                }
            }

            j += 1;
            if (j >= l.Count)
            {
                j = 0;
            }
            DataBridge2 dba = new DataBridge2()
            {
                parentid = pageDb.parentid,
                id = l[j].ID,
                title = l[j].Text
            };
            textTransition = "TLeft";
            // await Task.Delay(TimeSpan.FromMilliseconds(200));

            Debug.WriteLine("NextPage -> InitPage");
            InitPage(dba, true);
        }


        private void SetHeaderTexts(DataBridge2 db)
        {
            if (l.Count == 0)
            {
                CurrentItemHeader.Text = db.title;
                PhoneCurrentItemHeader.Text = db.title;
                return;
            }
            int j = 0;

            for (int i = 0; i < l.Count; i++)
            {
                if (l[i].ID == db.id)
                {
                    j = i;
                    break;
                }
            }

            int prev = j - 1;
            int next = j + 1;

            if (prev < 0)
                prev = l.Count - 1;
            if (next >= l.Count)
                next = 0;

            CurrentItemHeader.Text = l[j].Text.Replace("هٔ", "ة‌"); //Haz nim-faseleh after ة;
            PhoneCurrentItemHeader.Text = l[j].Text.Replace("هٔ", "ة‌"); //Haz nim-faseleh after ة;
            if ((prev != j) && (next != prev))
                PrevItemHeader.Text = l[prev].Text.Replace("هٔ", "ة‌"); //Haz nim-faseleh after ة;
            else
            {
                PrevItemHeader.Text = "";
                PrevItemHeader.Visibility = Visibility.Collapsed;
                PhonePrevItemHeader.Visibility = Visibility.Collapsed;
            }

            if (next != j)
                NextItemHeader.Text = l[next].Text.Replace("هٔ", "ة‌"); //Haz nim-faseleh after ة;
            else
            {
                NextItemHeader.Text = "";
                NextItemHeader.Visibility = Visibility.Collapsed;
                PhoneNextItemHeader.Visibility = Visibility.Collapsed;

                pivot.IsLocked = true;
            }

        }


        private void BackToggle_Click(object sender, RoutedEventArgs e)
        {
            Frame.GoBack();
        }

        private void CurrentItemHeader_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            TabletHeader.Height = e.NewSize.Height + 65;

            Content.Padding = new Thickness(0, 0, 0, 0);
        }

        private void PhoneCurrentItemHeader_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            PhoneHeader.Height = e.NewSize.Height + 30;

            if (UIViewSettings.GetForCurrentView().UserInteractionMode == UserInteractionMode.Mouse)
                Content.Padding = new Thickness(0, PhoneHeader.Height, 0, 0);

        }

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {

            try
            {
                dataTransferManager = DataTransferManager.GetForCurrentView();
                ShareHandler_DataRequested = new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(this.ShareTextHandler);
                dataTransferManager.DataRequested += ShareHandler_DataRequested;
            }
            catch (Exception ex)
            {
                throw new Exception("Error while contacting share handler.", ex);
            }

            if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
                Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;

            scrollSaveTimer.Interval = TimeSpan.FromSeconds(0.2);
            scrollSaveTimer.Tick += scrollSaveTimer_Tick;
        }

        private void HardwareButtons_BackPressed(object sender, Windows.Phone.UI.Input.BackPressedEventArgs e)
        {
            if (settingFlyoutOpened)
                SettingFlyout.Hide();
        }

        private void ShareTextHandler(DataTransferManager sender, DataRequestedEventArgs e)
        {
            DataRequest request = e.Request;
            request.Data.Properties.Title = App.dataSource.getPoetNameOfAPoem(pageDb.id) + ": " + pageDb.title;
            request.Data.Properties.Description = "اشتراک‌گذاری شعر";

            string sData = GetPoemString();
            request.Data.SetText(sData);
            request.Data.SetHtmlFormat(HtmlFormatHelper.CreateHtmlFormat(sData.Replace("\n", "<br />")));
        }

        bool animationRunning = false;
        private async void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (animationRunning)
                return;
            if (pivot.SelectedIndex == 1)
                return;

            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
            {
                animationRunning = true;
                await Task.Delay(50);
                if (pivot.SelectedIndex == 0)
                {
                    PreviousPage();
                    pivot.SelectedIndex = 2;
                }
                else
                {
                    NextPage();
                    pivot.SelectedIndex = 0;
                }

                await Task.Delay(100);
                pivot.SelectedIndex = 1;
                animationRunning = false;
            });
        }

        private void PrevItemHeader_Tapped(object sender, TappedRoutedEventArgs e)
        {
            pivot.SelectedIndex = 0;
        }

        private void NextItemHeader_Tapped(object sender, TappedRoutedEventArgs e)
        {
            pivot.SelectedIndex = 2;
        }

        private void CopyAppBarButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            DataPackage dp = new DataPackage();
            dp.SetText(GetPoemString());

            Clipboard.SetContent(dp);
        }

        private string GetPoemString()
        {
            List<VerseItem> verses = new List<VerseItem>();
            verses = App.dataSource.GetVerses(pageDb.id);

            string s = "";
            foreach (VerseItem item in verses)
            {
                s += item.hemistich1;
                if (item.hemistich2Visibility == Windows.UI.Xaml.Visibility.Visible)
                {
                    s += " / " + item.hemistich2;
                }
                s += " \r\n";
            }
            s += " \r\n - " + App.dataSource.getPoetNameOfAPoem(pageDb.id);
            s += " \r\n \r\n \r\n";
            s += "توسط نرم‌افزار گنجینه برای ویندوز ۱۰";

            return s;
        }

        private void ShareAppBarButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            Windows.ApplicationModel.DataTransfer.DataTransferManager.ShowShareUI();
        }

        private async void Flyout_Closed(object sender, object e)
        {
            settingFlyoutOpened = false;
            SettingAppBarButton.Background = new SolidColorBrush(Colors.Transparent);

            await App.dataSource.SaveSettings();
        }

        private void Flyout_Opened(object sender, object e)
        {
            settingFlyoutOpened = true;
            SettingAppBarButton.Background = new SolidColorBrush(Colors.DarkGray);
        }

        private void slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
        {
            if (!OnNavigatedToCalled)
                return;

            App.DefaultFontSize = e.NewValue;
        }

        private void FontsList_Loaded(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < App.fonts.Count; i++)
                if (App.fonts[i].Font == App.DefaultFont)
                    FontsList.SelectedIndex = i;
        }

        private void FontsList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            itemsControl.FontFamily = App.fonts[FontsList.SelectedIndex].Font;
            App.DefaultFont = App.fonts[FontsList.SelectedIndex].Font;
        }


        private void DeterminateFavButtonVisibility(DataBridge2 db)
        {
            try
            {
                var a = (from PoemItem p in App.favorites
                         where p.ID == db.id
                         select p).ToList();
                if (a.Count() > 0)
                {
                    FavAppBarButton.IsChecked = true;
                }
                else
                {
                    FavAppBarButton.IsChecked = false;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("Error while determinating relevant favorite button.", ex);
            }
        }

        private void FavAppBarButton_Tapped(object sender, TappedRoutedEventArgs e)
        {
            if (FavAppBarButton.IsChecked == true)
            {
                App.dataSource.AddToFavorites(pageDb.id);
            }
            else
            {
                App.dataSource.RemoveFromFavorites(pageDb.id);
            }
        }

        private void CopyFlyoutOK_Click(object sender, RoutedEventArgs e)
        {
            CopyFlyout.Hide();
        }


        private double GetScrollPosition(int poemId)
        {
            try
            {
                var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
                object scrollPos = localSettings.Values["scrollPosNew" + poemId.ToString()];
                if (scrollPos != null)
                {
                    double d;
                    if (double.TryParse(scrollPos.ToString(), out d))
                        return d;
                    else
                        return 0.0;
                }
                else
                {
                    /* Backward compatibiltiy with Ganjine for Windows Phone 8.1 */
                    object scrollPosOld = localSettings.Values["scrollPos" + poemId.ToString()];
                    if (scrollPosOld != null)
                    {
                        double d;

                        if (double.TryParse(scrollPosOld.ToString(), out d))
                        {
                            ScrollViewer scrollViewer = VisualChildFinder.FindVisualChild<ScrollViewer>(itemsControl);
                            return d / scrollViewer.ExtentHeight;
                        }
                        else
                            return 0.0;
                    }
                    else
                        return 0.0;
                }
            }
            catch
            {
                return 0.0;
            }
        }

        private void scrollSaveTimer_Tick(object sender, object e)
        {
            ScrollViewer scrollViewer = VisualChildFinder.FindVisualChild<ScrollViewer>(itemsControl);
            if (scrollViewer != null)
            {
                //Debug.WriteLine(scrollViewer.ActualHeight.ToString() + ", " + scrollViewer.ScrollableHeight.ToString() + ", " + scrollViewer.ViewportHeight.ToString() + ", " + scrollViewer.ExtentHeight.ToString());
                var localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
                localSettings.Values["scrollPosNew" + pageDb.id] = scrollViewer.VerticalOffset / scrollViewer.ExtentHeight;
                Debug.WriteLine(pageDb.id.ToString() + " : " + scrollViewer.VerticalOffset.ToString() + " ... " + scrollViewer.ExtentHeight.ToString());
            }

        }

    }
}
